home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkRectOval.c < prev    next >
C/C++ Source or Header  |  1995-03-16  |  31KB  |  1,005 lines

  1. /* 
  2.  * tkRectOval.c --
  3.  *
  4.  *    This file implements rectangle and oval items for canvas
  5.  *    widgets.
  6.  *
  7.  * Copyright (c) 1991-1994 The Regents of the University of California.
  8.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  */
  13.  
  14. static char sccsid[] = "@(#) tkRectOval.c 1.31 95/01/03 17:06:03";
  15.  
  16. #include <stdio.h>
  17. #include "tk.h"
  18. #include "tkInt.h"
  19. #include "tkPort.h"
  20.  
  21. /*
  22.  * The structure below defines the record for each rectangle/oval item.
  23.  */
  24.  
  25. typedef struct RectOvalItem  {
  26.     Tk_Item header;        /* Generic stuff that's the same for all
  27.                  * types.  MUST BE FIRST IN STRUCTURE. */
  28.     double bbox[4];        /* Coordinates of bounding box for rectangle
  29.                  * or oval (x1, y1, x2, y2).  Item includes
  30.                  * x1 and x2 but not y1 and y2. */
  31.     int width;            /* Width of outline. */
  32.     XColor *outlineColor;    /* Color for outline. */
  33.     XColor *fillColor;        /* Color for filling rectangle/oval. */
  34.     Pixmap fillStipple;        /* Stipple bitmap for filling item. */
  35.     GC outlineGC;        /* Graphics context for outline. */
  36.     GC fillGC;            /* Graphics context for filling item. */
  37. } RectOvalItem;
  38.  
  39. /*
  40.  * Information used for parsing configuration specs:
  41.  */
  42.  
  43. static Tk_ConfigSpec configSpecs[] = {
  44.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  45.     (char *) NULL, Tk_Offset(RectOvalItem, fillColor), TK_CONFIG_NULL_OK},
  46.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  47.     "black", Tk_Offset(RectOvalItem, outlineColor), TK_CONFIG_NULL_OK},
  48.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  49.     (char *) NULL, Tk_Offset(RectOvalItem, fillStipple), TK_CONFIG_NULL_OK},
  50.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  51.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tk_CanvasTagsOption},
  52.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  53.     "1", Tk_Offset(RectOvalItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  54.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  55.     (char *) NULL, 0, 0}
  56. };
  57.  
  58. /*
  59.  * Prototypes for procedures defined in this file:
  60.  */
  61.  
  62. static void        ComputeRectOvalBbox _ANSI_ARGS_((Tk_Canvas canvas,
  63.                 RectOvalItem *rectOvalPtr));
  64. static int        ConfigureRectOval _ANSI_ARGS_((Tcl_Interp *interp,
  65.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  66.                 char **argv, int flags));
  67. static int        CreateRectOval _ANSI_ARGS_((Tcl_Interp *interp,
  68.                 Tk_Canvas canvas, struct Tk_Item *itemPtr,
  69.                 int argc, char **argv));
  70. static void        DeleteRectOval _ANSI_ARGS_((Tk_Canvas canvas,
  71.                 Tk_Item *itemPtr, Display *display));
  72. static void        DisplayRectOval _ANSI_ARGS_((Tk_Canvas canvas,
  73.                 Tk_Item *itemPtr, Display *display, Drawable dst,
  74.                 int x, int y, int width, int height));
  75. static int        OvalToArea _ANSI_ARGS_((Tk_Canvas canvas,
  76.                 Tk_Item *itemPtr, double *areaPtr));
  77. static double        OvalToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  78.                 Tk_Item *itemPtr, double *pointPtr));
  79. static int        RectOvalCoords _ANSI_ARGS_((Tcl_Interp *interp,
  80.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  81.                 char **argv));
  82. static int        RectOvalToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  83.                 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  84. static int        RectToArea _ANSI_ARGS_((Tk_Canvas canvas,
  85.                 Tk_Item *itemPtr, double *areaPtr));
  86. static double        RectToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  87.                 Tk_Item *itemPtr, double *pointPtr));
  88. static void        ScaleRectOval _ANSI_ARGS_((Tk_Canvas canvas,
  89.                 Tk_Item *itemPtr, double originX, double originY,
  90.                 double scaleX, double scaleY));
  91. static void        TranslateRectOval _ANSI_ARGS_((Tk_Canvas canvas,
  92.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  93.  
  94. /*
  95.  * The structures below defines the rectangle and oval item types
  96.  * by means of procedures that can be invoked by generic item code.
  97.  */
  98.  
  99. Tk_ItemType tkRectangleType = {
  100.     "rectangle",            /* name */
  101.     sizeof(RectOvalItem),        /* itemSize */
  102.     CreateRectOval,            /* createProc */
  103.     configSpecs,            /* configSpecs */
  104.     ConfigureRectOval,            /* configureProc */
  105.     RectOvalCoords,            /* coordProc */
  106.     DeleteRectOval,            /* deleteProc */
  107.     DisplayRectOval,            /* displayProc */
  108.     0,                    /* alwaysRedraw */
  109.     RectToPoint,            /* pointProc */
  110.     RectToArea,                /* areaProc */
  111.     RectOvalToPostscript,        /* postscriptProc */
  112.     ScaleRectOval,            /* scaleProc */
  113.     TranslateRectOval,            /* translateProc */
  114.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  115.     (Tk_ItemCursorProc *) NULL,        /* icursorProc */
  116.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  117.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  118.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  119.     (Tk_ItemType *) NULL        /* nextPtr */
  120. };
  121.  
  122. Tk_ItemType tkOvalType = {
  123.     "oval",                /* name */
  124.     sizeof(RectOvalItem),        /* itemSize */
  125.     CreateRectOval,            /* createProc */
  126.     configSpecs,            /* configSpecs */
  127.     ConfigureRectOval,            /* configureProc */
  128.     RectOvalCoords,            /* coordProc */
  129.     DeleteRectOval,            /* deleteProc */
  130.     DisplayRectOval,            /* displayProc */
  131.     0,                    /* alwaysRedraw */
  132.     OvalToPoint,            /* pointProc */
  133.     OvalToArea,                /* areaProc */
  134.     RectOvalToPostscript,        /* postscriptProc */
  135.     ScaleRectOval,            /* scaleProc */
  136.     TranslateRectOval,            /* translateProc */
  137.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  138.     (Tk_ItemCursorProc *) NULL,        /* cursorProc */
  139.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  140.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  141.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  142.     (Tk_ItemType *) NULL        /* nextPtr */
  143. };
  144.  
  145. /*
  146.  *--------------------------------------------------------------
  147.  *
  148.  * CreateRectOval --
  149.  *
  150.  *    This procedure is invoked to create a new rectangle
  151.  *    or oval item in a canvas.
  152.  *
  153.  * Results:
  154.  *    A standard Tcl return value.  If an error occurred in
  155.  *    creating the item, then an error message is left in
  156.  *    interp->result;  in this case itemPtr is left uninitialized,
  157.  *    so it can be safely freed by the caller.
  158.  *
  159.  * Side effects:
  160.  *    A new rectangle or oval item is created.
  161.  *
  162.  *--------------------------------------------------------------
  163.  */
  164.  
  165. static int
  166. CreateRectOval(interp, canvas, itemPtr, argc, argv)
  167.     Tcl_Interp *interp;            /* For error reporting. */
  168.     Tk_Canvas canvas;            /* Canvas to hold new item. */
  169.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  170.                      * has been initialized by caller. */
  171.     int argc;                /* Number of arguments in argv. */
  172.     char **argv;            /* Arguments describing rectangle. */
  173. {
  174.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  175.  
  176.     if (argc < 4) {
  177.     Tcl_AppendResult(interp, "wrong # args:  should be \"",
  178.         Tk_PathName(Tk_CanvasTkwin(canvas)), "\" create ",
  179.         itemPtr->typePtr->name, " x1 y1 x2 y2 ?options?",
  180.         (char *) NULL);
  181.     return TCL_ERROR;
  182.     }
  183.  
  184.     /*
  185.      * Carry out initialization that is needed in order to clean
  186.      * up after errors during the the remainder of this procedure.
  187.      */
  188.  
  189.     rectOvalPtr->width = 1;
  190.     rectOvalPtr->outlineColor = NULL;
  191.     rectOvalPtr->fillColor = NULL;
  192.     rectOvalPtr->fillStipple = None;
  193.     rectOvalPtr->outlineGC = None;
  194.     rectOvalPtr->fillGC = None;
  195.  
  196.     /*
  197.      * Process the arguments to fill in the item record.
  198.      */
  199.  
  200.     if ((Tk_CanvasGetCoord(interp, canvas, argv[0],
  201.         &rectOvalPtr->bbox[0]) != TCL_OK)
  202.         || (Tk_CanvasGetCoord(interp, canvas, argv[1],
  203.         &rectOvalPtr->bbox[1]) != TCL_OK)
  204.         || (Tk_CanvasGetCoord(interp, canvas, argv[2],
  205.             &rectOvalPtr->bbox[2]) != TCL_OK)
  206.         || (Tk_CanvasGetCoord(interp, canvas, argv[3],
  207.             &rectOvalPtr->bbox[3]) != TCL_OK)) {
  208.     return TCL_ERROR;
  209.     }
  210.  
  211.     if (ConfigureRectOval(interp, canvas, itemPtr, argc-4, argv+4, 0)
  212.         != TCL_OK) {
  213.     DeleteRectOval(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  214.     return TCL_ERROR;
  215.     }
  216.     return TCL_OK;
  217. }
  218.  
  219. /*
  220.  *--------------------------------------------------------------
  221.  *
  222.  * RectOvalCoords --
  223.  *
  224.  *    This procedure is invoked to process the "coords" widget
  225.  *    command on rectangles and ovals.  See the user documentation
  226.  *    for details on what it does.
  227.  *
  228.  * Results:
  229.  *    Returns TCL_OK or TCL_ERROR, and sets interp->result.
  230.  *
  231.  * Side effects:
  232.  *    The coordinates for the given item may be changed.
  233.  *
  234.  *--------------------------------------------------------------
  235.  */
  236.  
  237. static int
  238. RectOvalCoords(interp, canvas, itemPtr, argc, argv)
  239.     Tcl_Interp *interp;            /* Used for error reporting. */
  240.     Tk_Canvas canvas;            /* Canvas containing item. */
  241.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  242.                      * read or modified. */
  243.     int argc;                /* Number of coordinates supplied in
  244.                      * argv. */
  245.     char **argv;            /* Array of coordinates: x1, y1,
  246.                      * x2, y2, ... */
  247. {
  248.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  249.     char c0[TCL_DOUBLE_SPACE], c1[TCL_DOUBLE_SPACE];
  250.     char c2[TCL_DOUBLE_SPACE], c3[TCL_DOUBLE_SPACE];
  251.  
  252.     if (argc == 0) {
  253.     Tcl_PrintDouble(interp, rectOvalPtr->bbox[0], c0);
  254.     Tcl_PrintDouble(interp, rectOvalPtr->bbox[1], c1);
  255.     Tcl_PrintDouble(interp, rectOvalPtr->bbox[2], c2);
  256.     Tcl_PrintDouble(interp, rectOvalPtr->bbox[3], c3);
  257.     Tcl_AppendResult(interp, c0, " ", c1, " ", c2, " ", c3,
  258.         (char *) NULL);
  259.     } else if (argc == 4) {
  260.     if ((Tk_CanvasGetCoord(interp, canvas, argv[0],
  261.             &rectOvalPtr->bbox[0]) != TCL_OK)
  262.         || (Tk_CanvasGetCoord(interp, canvas, argv[1],
  263.             &rectOvalPtr->bbox[1]) != TCL_OK)
  264.         || (Tk_CanvasGetCoord(interp, canvas, argv[2],
  265.             &rectOvalPtr->bbox[2]) != TCL_OK)
  266.         || (Tk_CanvasGetCoord(interp, canvas, argv[3],
  267.             &rectOvalPtr->bbox[3]) != TCL_OK)) {
  268.         return TCL_ERROR;
  269.     }
  270.     ComputeRectOvalBbox(canvas, rectOvalPtr);
  271.     } else {
  272.     sprintf(interp->result,
  273.         "wrong # coordinates:  expected 0 or 4, got %d",
  274.         argc);
  275.     return TCL_ERROR;
  276.     }
  277.     return TCL_OK;
  278. }
  279.  
  280. /*
  281.  *--------------------------------------------------------------
  282.  *
  283.  * ConfigureRectOval --
  284.  *
  285.  *    This procedure is invoked to configure various aspects
  286.  *    of a rectangle or oval item, such as its border and
  287.  *    background colors.
  288.  *
  289.  * Results:
  290.  *    A standard Tcl result code.  If an error occurs, then
  291.  *    an error message is left in interp->result.
  292.  *
  293.  * Side effects:
  294.  *    Configuration information, such as colors and stipple
  295.  *    patterns, may be set for itemPtr.
  296.  *
  297.  *--------------------------------------------------------------
  298.  */
  299.  
  300. static int
  301. ConfigureRectOval(interp, canvas, itemPtr, argc, argv, flags)
  302.     Tcl_Interp *interp;        /* Used for error reporting. */
  303.     Tk_Canvas canvas;        /* Canvas containing itemPtr. */
  304.     Tk_Item *itemPtr;        /* Rectangle item to reconfigure. */
  305.     int argc;            /* Number of elements in argv.  */
  306.     char **argv;        /* Arguments describing things to configure. */
  307.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  308. {
  309.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  310.     XGCValues gcValues;
  311.     GC newGC;
  312.     unsigned long mask;
  313.     Tk_Window tkwin;
  314.  
  315.     tkwin = Tk_CanvasTkwin(canvas);
  316.     if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv,
  317.         (char *) rectOvalPtr, flags) != TCL_OK) {
  318.     return TCL_ERROR;
  319.     }
  320.  
  321.     /*
  322.      * A few of the options require additional processing, such as
  323.      * graphics contexts.
  324.      */
  325.  
  326.     if (rectOvalPtr->width < 1) {
  327.     rectOvalPtr->width = 1;
  328.     }
  329.     if (rectOvalPtr->outlineColor == NULL) {
  330.     newGC = None;
  331.     } else {
  332.     gcValues.foreground = rectOvalPtr->outlineColor->pixel;
  333.     gcValues.cap_style = CapProjecting;
  334.     gcValues.line_width = rectOvalPtr->width;
  335.     mask = GCForeground|GCCapStyle|GCLineWidth;
  336.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  337.     }
  338.     if (rectOvalPtr->outlineGC != None) {
  339.     Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->outlineGC);
  340.     }
  341.     rectOvalPtr->outlineGC = newGC;
  342.  
  343.     if (rectOvalPtr->fillColor == NULL) {
  344.     newGC = None;
  345.     } else {
  346.     gcValues.foreground = rectOvalPtr->fillColor->pixel;
  347.     if (rectOvalPtr->fillStipple != None) {
  348.         gcValues.stipple = rectOvalPtr->fillStipple;
  349.         gcValues.fill_style = FillStippled;
  350.         mask = GCForeground|GCStipple|GCFillStyle;
  351.     } else {
  352.         mask = GCForeground;
  353.     }
  354.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  355.     }
  356.     if (rectOvalPtr->fillGC != None) {
  357.     Tk_FreeGC(Tk_Display(tkwin), rectOvalPtr->fillGC);
  358.     }
  359.     rectOvalPtr->fillGC = newGC;
  360.     ComputeRectOvalBbox(canvas, rectOvalPtr);
  361.  
  362.     return TCL_OK;
  363. }
  364.  
  365. /*
  366.  *--------------------------------------------------------------
  367.  *
  368.  * DeleteRectOval --
  369.  *
  370.  *    This procedure is called to clean up the data structure
  371.  *    associated with a rectangle or oval item.
  372.  *
  373.  * Results:
  374.  *    None.
  375.  *
  376.  * Side effects:
  377.  *    Resources associated with itemPtr are released.
  378.  *
  379.  *--------------------------------------------------------------
  380.  */
  381.  
  382. static void
  383. DeleteRectOval(canvas, itemPtr, display)
  384.     Tk_Canvas canvas;            /* Info about overall widget. */
  385.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  386.     Display *display;            /* Display containing window for
  387.                      * canvas. */
  388. {
  389.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  390.  
  391.     if (rectOvalPtr->outlineColor != NULL) {
  392.     Tk_FreeColor(rectOvalPtr->outlineColor);
  393.     }
  394.     if (rectOvalPtr->fillColor != NULL) {
  395.     Tk_FreeColor(rectOvalPtr->fillColor);
  396.     }
  397.     if (rectOvalPtr->fillStipple != None) {
  398.     Tk_FreeBitmap(display, rectOvalPtr->fillStipple);
  399.     }
  400.     if (rectOvalPtr->outlineGC != None) {
  401.     Tk_FreeGC(display, rectOvalPtr->outlineGC);
  402.     }
  403.     if (rectOvalPtr->fillGC != None) {
  404.     Tk_FreeGC(display, rectOvalPtr->fillGC);
  405.     }
  406. }
  407.  
  408. /*
  409.  *--------------------------------------------------------------
  410.  *
  411.  * ComputeRectOvalBbox --
  412.  *
  413.  *    This procedure is invoked to compute the bounding box of
  414.  *    all the pixels that may be drawn as part of a rectangle
  415.  *    or oval.
  416.  *
  417.  * Results:
  418.  *    None.
  419.  *
  420.  * Side effects:
  421.  *    The fields x1, y1, x2, and y2 are updated in the header
  422.  *    for itemPtr.
  423.  *
  424.  *--------------------------------------------------------------
  425.  */
  426.  
  427.     /* ARGSUSED */
  428. static void
  429. ComputeRectOvalBbox(canvas, rectOvalPtr)
  430.     Tk_Canvas canvas;            /* Canvas that contains item. */
  431.     RectOvalItem *rectOvalPtr;        /* Item whose bbox is to be
  432.                      * recomputed. */
  433. {
  434.     int bloat;
  435.  
  436.     /*
  437.      * Make sure that the first coordinates are the lowest ones.
  438.      */
  439.  
  440.     if (rectOvalPtr->bbox[1] > rectOvalPtr->bbox[3]) {
  441.     double tmp;
  442.     tmp = rectOvalPtr->bbox[3];
  443.     rectOvalPtr->bbox[3] = rectOvalPtr->bbox[1];
  444.     rectOvalPtr->bbox[1] = tmp;
  445.     }
  446.     if (rectOvalPtr->bbox[0] > rectOvalPtr->bbox[2]) {
  447.     double tmp;
  448.     tmp = rectOvalPtr->bbox[2];
  449.     rectOvalPtr->bbox[2] = rectOvalPtr->bbox[0];
  450.     rectOvalPtr->bbox[0] = tmp;
  451.     }
  452.  
  453.     if (rectOvalPtr->outlineColor == NULL) {
  454.     bloat = 0;
  455.     } else {
  456.     bloat = (rectOvalPtr->width+1)/2;
  457.     }
  458.     rectOvalPtr->header.x1 = rectOvalPtr->bbox[0] - bloat;
  459.     rectOvalPtr->header.y1 = rectOvalPtr->bbox[1] - bloat;
  460.     rectOvalPtr->header.x2 = rectOvalPtr->bbox[2] + bloat + 1;
  461.     rectOvalPtr->header.y2 = rectOvalPtr->bbox[3] + bloat + 1;
  462. }
  463.  
  464. /*
  465.  *--------------------------------------------------------------
  466.  *
  467.  * DisplayRectOval --
  468.  *
  469.  *    This procedure is invoked to draw a rectangle or oval
  470.  *    item in a given drawable.
  471.  *
  472.  * Results:
  473.  *    None.
  474.  *
  475.  * Side effects:
  476.  *    ItemPtr is drawn in drawable using the transformation
  477.  *    information in canvas.
  478.  *
  479.  *--------------------------------------------------------------
  480.  */
  481.  
  482. static void
  483. DisplayRectOval(canvas, itemPtr, display, drawable, x, y, width, height)
  484.     Tk_Canvas canvas;            /* Canvas that contains item. */
  485.     Tk_Item *itemPtr;            /* Item to be displayed. */
  486.     Display *display;            /* Display on which to draw item. */
  487.     Drawable drawable;            /* Pixmap or window in which to draw
  488.                      * item. */
  489.     int x, y, width, height;        /* Describes region of canvas that
  490.                      * must be redisplayed (not used). */
  491. {
  492.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  493.     short x1, y1, x2, y2;
  494.  
  495.     /*
  496.      * Compute the screen coordinates of the bounding box for the item.
  497.      * Make sure that the bbox is at least one pixel large, since some
  498.      * X servers will die if it isn't.
  499.      */
  500.  
  501.     Tk_CanvasDrawableCoords(canvas, rectOvalPtr->bbox[0], rectOvalPtr->bbox[1],
  502.         &x1, &y1);
  503.     Tk_CanvasDrawableCoords(canvas, rectOvalPtr->bbox[2], rectOvalPtr->bbox[3],
  504.         &x2, &y2);
  505.     if (x2 <= x1) {
  506.     x2 = x1+1;
  507.     }
  508.     if (y2 <= y1) {
  509.     y2 = y1+1;
  510.     }
  511.  
  512.     /*
  513.      * Display filled part first (if wanted), then outline.  If we're
  514.      * stippling, then modify the stipple offset in the GC.  Be sure to
  515.      * reset the offset when done, since the GC is supposed to be
  516.      * read-only.
  517.      */
  518.  
  519.     if (rectOvalPtr->fillGC != None) {
  520.     if (rectOvalPtr->fillStipple != None) {
  521.         Tk_CanvasSetStippleOrigin(canvas, rectOvalPtr->fillGC);
  522.     }
  523.     if (rectOvalPtr->header.typePtr == &tkRectangleType) {
  524.         XFillRectangle(display, drawable, rectOvalPtr->fillGC,
  525.             x1, y1, (unsigned int) (x2-x1), (unsigned int) (y2-y1));
  526.     } else {
  527.         XFillArc(display, drawable, rectOvalPtr->fillGC,
  528.             x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1),
  529.             0, 360*64);
  530.     }
  531.     if (rectOvalPtr->fillStipple != None) {
  532.         XSetTSOrigin(display, rectOvalPtr->fillGC, 0, 0);
  533.     }
  534.     }
  535.     if (rectOvalPtr->outlineGC != None) {
  536.     if (rectOvalPtr->header.typePtr == &tkRectangleType) {
  537.         XDrawRectangle(display, drawable, rectOvalPtr->outlineGC,
  538.             x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1));
  539.     } else {
  540.         XDrawArc(display, drawable, rectOvalPtr->outlineGC,
  541.             x1, y1, (unsigned) (x2-x1), (unsigned) (y2-y1), 0, 360*64);
  542.     }
  543.     }
  544. }
  545.  
  546. /*
  547.  *--------------------------------------------------------------
  548.  *
  549.  * RectToPoint --
  550.  *
  551.  *    Computes the distance from a given point to a given
  552.  *    rectangle, in canvas units.
  553.  *
  554.  * Results:
  555.  *    The return value is 0 if the point whose x and y coordinates
  556.  *    are coordPtr[0] and coordPtr[1] is inside the rectangle.  If the
  557.  *    point isn't inside the rectangle then the return value is the
  558.  *    distance from the point to the rectangle.  If itemPtr is filled,
  559.  *    then anywhere in the interior is considered "inside"; if
  560.  *    itemPtr isn't filled, then "inside" means only the area
  561.  *    occupied by the outline.
  562.  *
  563.  * Side effects:
  564.  *    None.
  565.  *
  566.  *--------------------------------------------------------------
  567.  */
  568.  
  569.     /* ARGSUSED */
  570. static double
  571. RectToPoint(canvas, itemPtr, pointPtr)
  572.     Tk_Canvas canvas;        /* Canvas containing item. */
  573.     Tk_Item *itemPtr;        /* Item to check against point. */
  574.     double *pointPtr;        /* Pointer to x and y coordinates. */
  575. {
  576.     RectOvalItem *rectPtr = (RectOvalItem *) itemPtr;
  577.     double xDiff, yDiff, x1, y1, x2, y2, inc, tmp;
  578.  
  579.     /*
  580.      * Generate a new larger rectangle that includes the border
  581.      * width, if there is one.
  582.      */
  583.  
  584.     x1 = rectPtr->bbox[0];
  585.     y1 = rectPtr->bbox[1];
  586.     x2 = rectPtr->bbox[2];
  587.     y2 = rectPtr->bbox[3];
  588.     if (rectPtr->outlineGC != None) {
  589.     inc = rectPtr->width/2.0;
  590.     x1 -= inc;
  591.     y1 -= inc;
  592.     x2 += inc;
  593.     y2 += inc;
  594.     }
  595.  
  596.     /*
  597.      * If the point is inside the rectangle, handle specially:
  598.      * distance is 0 if rectangle is filled, otherwise compute
  599.      * distance to nearest edge of rectangle and subtract width
  600.      * of edge.
  601.      */
  602.  
  603.     if ((pointPtr[0] >= x1) && (pointPtr[0] < x2)
  604.         && (pointPtr[1] >= y1) && (pointPtr[1] < y2)) {
  605.     if ((rectPtr->fillGC != None) || (rectPtr->outlineGC == None)) {
  606.         return 0.0;
  607.     }
  608.     xDiff = pointPtr[0] - x1;
  609.     tmp = x2 - pointPtr[0];
  610.     if (tmp < xDiff) {
  611.         xDiff = tmp;
  612.     }
  613.     yDiff = pointPtr[1] - y1;
  614.     tmp = y2 - pointPtr[1];
  615.     if (tmp < yDiff) {
  616.         yDiff = tmp;
  617.     }
  618.     if (yDiff < xDiff) {
  619.         xDiff = yDiff;
  620.     }
  621.     xDiff -= rectPtr->width;
  622.     if (xDiff < 0.0) {
  623.         return 0.0;
  624.     }
  625.     return xDiff;
  626.     }
  627.  
  628.     /*
  629.      * Point is outside rectangle.
  630.      */
  631.  
  632.     if (pointPtr[0] < x1) {
  633.     xDiff = x1 - pointPtr[0];
  634.     } else if (pointPtr[0] > x2)  {
  635.     xDiff = pointPtr[0] - x2;
  636.     } else {
  637.     xDiff = 0;
  638.     }
  639.  
  640.     if (pointPtr[1] < y1) {
  641.     yDiff = y1 - pointPtr[1];
  642.     } else if (pointPtr[1] > y2)  {
  643.     yDiff = pointPtr[1] - y2;
  644.     } else {
  645.     yDiff = 0;
  646.     }
  647.  
  648.     return hypot(xDiff, yDiff);
  649. }
  650.  
  651. /*
  652.  *--------------------------------------------------------------
  653.  *
  654.  * OvalToPoint --
  655.  *
  656.  *    Computes the distance from a given point to a given
  657.  *    oval, in canvas units.
  658.  *
  659.  * Results:
  660.  *    The return value is 0 if the point whose x and y coordinates
  661.  *    are coordPtr[0] and coordPtr[1] is inside the oval.  If the
  662.  *    point isn't inside the oval then the return value is the
  663.  *    distance from the point to the oval.  If itemPtr is filled,
  664.  *    then anywhere in the interior is considered "inside"; if
  665.  *    itemPtr isn't filled, then "inside" means only the area
  666.  *    occupied by the outline.
  667.  *
  668.  * Side effects:
  669.  *    None.
  670.  *
  671.  *--------------------------------------------------------------
  672.  */
  673.  
  674.     /* ARGSUSED */
  675. static double
  676. OvalToPoint(canvas, itemPtr, pointPtr)
  677.     Tk_Canvas canvas;        /* Canvas containing item. */
  678.     Tk_Item *itemPtr;        /* Item to check against point. */
  679.     double *pointPtr;        /* Pointer to x and y coordinates. */
  680. {
  681.     RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr;
  682.     double width;
  683.     int filled;
  684.  
  685.     width = ovalPtr->width;
  686.     filled = ovalPtr->fillGC != None;
  687.     if (ovalPtr->outlineGC == None) {
  688.     width = 0.0;
  689.     filled = 1;
  690.     }
  691.     return TkOvalToPoint(ovalPtr->bbox, width, filled, pointPtr);
  692. }
  693.  
  694. /*
  695.  *--------------------------------------------------------------
  696.  *
  697.  * RectToArea --
  698.  *
  699.  *    This procedure is called to determine whether an item
  700.  *    lies entirely inside, entirely outside, or overlapping
  701.  *    a given rectangle.
  702.  *
  703.  * Results:
  704.  *    -1 is returned if the item is entirely outside the area
  705.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  706.  *    inside the given area.
  707.  *
  708.  * Side effects:
  709.  *    None.
  710.  *
  711.  *--------------------------------------------------------------
  712.  */
  713.  
  714.     /* ARGSUSED */
  715. static int
  716. RectToArea(canvas, itemPtr, areaPtr)
  717.     Tk_Canvas canvas;        /* Canvas containing item. */
  718.     Tk_Item *itemPtr;        /* Item to check against rectangle. */
  719.     double *areaPtr;        /* Pointer to array of four coordinates
  720.                  * (x1, y1, x2, y2) describing rectangular
  721.                  * area.  */
  722. {
  723.     RectOvalItem *rectPtr = (RectOvalItem *) itemPtr;
  724.     double halfWidth;
  725.  
  726.     halfWidth = rectPtr->width/2.0;
  727.     if (rectPtr->outlineGC == None) {
  728.     halfWidth = 0.0;
  729.     }
  730.  
  731.     if ((areaPtr[2] <= (rectPtr->bbox[0] - halfWidth))
  732.         || (areaPtr[0] >= (rectPtr->bbox[2] + halfWidth))
  733.         || (areaPtr[3] <= (rectPtr->bbox[1] - halfWidth))
  734.         || (areaPtr[1] >= (rectPtr->bbox[3] + halfWidth))) {
  735.     return -1;
  736.     }
  737.     if ((rectPtr->fillGC == None) && (rectPtr->outlineGC != None)
  738.         && (areaPtr[0] >= (rectPtr->bbox[0] + halfWidth))
  739.         && (areaPtr[1] >= (rectPtr->bbox[1] + halfWidth))
  740.         && (areaPtr[2] <= (rectPtr->bbox[2] - halfWidth))
  741.         && (areaPtr[3] <= (rectPtr->bbox[3] - halfWidth))) {
  742.     return -1;
  743.     }
  744.     if ((areaPtr[0] <= (rectPtr->bbox[0] - halfWidth))
  745.         && (areaPtr[1] <= (rectPtr->bbox[1] - halfWidth))
  746.         && (areaPtr[2] >= (rectPtr->bbox[2] + halfWidth))
  747.         && (areaPtr[3] >= (rectPtr->bbox[3] + halfWidth))) {
  748.     return 1;
  749.     }
  750.     return 0;
  751. }
  752.  
  753. /*
  754.  *--------------------------------------------------------------
  755.  *
  756.  * OvalToArea --
  757.  *
  758.  *    This procedure is called to determine whether an item
  759.  *    lies entirely inside, entirely outside, or overlapping
  760.  *    a given rectangular area.
  761.  *
  762.  * Results:
  763.  *    -1 is returned if the item is entirely outside the area
  764.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  765.  *    inside the given area.
  766.  *
  767.  * Side effects:
  768.  *    None.
  769.  *
  770.  *--------------------------------------------------------------
  771.  */
  772.  
  773.     /* ARGSUSED */
  774. static int
  775. OvalToArea(canvas, itemPtr, areaPtr)
  776.     Tk_Canvas canvas;        /* Canvas containing item. */
  777.     Tk_Item *itemPtr;        /* Item to check against oval. */
  778.     double *areaPtr;        /* Pointer to array of four coordinates
  779.                  * (x1, y1, x2, y2) describing rectangular
  780.                  * area.  */
  781. {
  782.     RectOvalItem *ovalPtr = (RectOvalItem *) itemPtr;
  783.     double oval[4], halfWidth;
  784.     int result;
  785.  
  786.     /*
  787.      * Expand the oval to include the width of the outline, if any.
  788.      */
  789.  
  790.     halfWidth = ovalPtr->width/2.0;
  791.     if (ovalPtr->outlineGC == None) {
  792.     halfWidth = 0.0;
  793.     }
  794.     oval[0] = ovalPtr->bbox[0] - halfWidth;
  795.     oval[1] = ovalPtr->bbox[1] - halfWidth;
  796.     oval[2] = ovalPtr->bbox[2] + halfWidth;
  797.     oval[3] = ovalPtr->bbox[3] + halfWidth;
  798.  
  799.     result = TkOvalToArea(oval, areaPtr);
  800.  
  801.     /*
  802.      * If the rectangle appears to overlap the oval and the oval
  803.      * isn't filled, do one more check to see if perhaps all four
  804.      * of the rectangle's corners are totally inside the oval's
  805.      * unfilled center, in which case we should return "outside".
  806.      */
  807.  
  808.     if ((result == 0) && (ovalPtr->outlineGC != None)
  809.         && (ovalPtr->fillGC == None)) {
  810.     double centerX, centerY, width, height;
  811.     double xDelta1, yDelta1, xDelta2, yDelta2;
  812.  
  813.     centerX = (ovalPtr->bbox[0] + ovalPtr->bbox[2])/2.0;
  814.     centerY = (ovalPtr->bbox[1] + ovalPtr->bbox[3])/2.0;
  815.     width = (ovalPtr->bbox[2] - ovalPtr->bbox[0])/2.0 - halfWidth;
  816.     height = (ovalPtr->bbox[3] - ovalPtr->bbox[1])/2.0 - halfWidth;
  817.     xDelta1 = (areaPtr[0] - centerX)/width;
  818.     xDelta1 *= xDelta1;
  819.     yDelta1 = (areaPtr[1] - centerY)/height;
  820.     yDelta1 *= yDelta1;
  821.     xDelta2 = (areaPtr[2] - centerX)/width;
  822.     xDelta2 *= xDelta2;
  823.     yDelta2 = (areaPtr[3] - centerY)/height;
  824.     yDelta2 *= yDelta2;
  825.     if (((xDelta1 + yDelta1) < 1.0)
  826.         && ((xDelta1 + yDelta2) < 1.0)
  827.         && ((xDelta2 + yDelta1) < 1.0)
  828.         && ((xDelta2 + yDelta2) < 1.0)) {
  829.         return -1;
  830.     }
  831.     }
  832.     return result;
  833. }
  834.  
  835. /*
  836.  *--------------------------------------------------------------
  837.  *
  838.  * ScaleRectOval --
  839.  *
  840.  *    This procedure is invoked to rescale a rectangle or oval
  841.  *    item.
  842.  *
  843.  * Results:
  844.  *    None.
  845.  *
  846.  * Side effects:
  847.  *    The rectangle or oval referred to by itemPtr is rescaled
  848.  *    so that the following transformation is applied to all
  849.  *    point coordinates:
  850.  *        x' = originX + scaleX*(x-originX)
  851.  *        y' = originY + scaleY*(y-originY)
  852.  *
  853.  *--------------------------------------------------------------
  854.  */
  855.  
  856. static void
  857. ScaleRectOval(canvas, itemPtr, originX, originY, scaleX, scaleY)
  858.     Tk_Canvas canvas;            /* Canvas containing rectangle. */
  859.     Tk_Item *itemPtr;            /* Rectangle to be scaled. */
  860.     double originX, originY;        /* Origin about which to scale rect. */
  861.     double scaleX;            /* Amount to scale in X direction. */
  862.     double scaleY;            /* Amount to scale in Y direction. */
  863. {
  864.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  865.  
  866.     rectOvalPtr->bbox[0] = originX + scaleX*(rectOvalPtr->bbox[0] - originX);
  867.     rectOvalPtr->bbox[1] = originY + scaleY*(rectOvalPtr->bbox[1] - originY);
  868.     rectOvalPtr->bbox[2] = originX + scaleX*(rectOvalPtr->bbox[2] - originX);
  869.     rectOvalPtr->bbox[3] = originY + scaleY*(rectOvalPtr->bbox[3] - originY);
  870.     ComputeRectOvalBbox(canvas, rectOvalPtr);
  871. }
  872.  
  873. /*
  874.  *--------------------------------------------------------------
  875.  *
  876.  * TranslateRectOval --
  877.  *
  878.  *    This procedure is called to move a rectangle or oval by a
  879.  *    given amount.
  880.  *
  881.  * Results:
  882.  *    None.
  883.  *
  884.  * Side effects:
  885.  *    The position of the rectangle or oval is offset by
  886.  *    (xDelta, yDelta), and the bounding box is updated in the
  887.  *    generic part of the item structure.
  888.  *
  889.  *--------------------------------------------------------------
  890.  */
  891.  
  892. static void
  893. TranslateRectOval(canvas, itemPtr, deltaX, deltaY)
  894.     Tk_Canvas canvas;            /* Canvas containing item. */
  895.     Tk_Item *itemPtr;            /* Item that is being moved. */
  896.     double deltaX, deltaY;        /* Amount by which item is to be
  897.                      * moved. */
  898. {
  899.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  900.  
  901.     rectOvalPtr->bbox[0] += deltaX;
  902.     rectOvalPtr->bbox[1] += deltaY;
  903.     rectOvalPtr->bbox[2] += deltaX;
  904.     rectOvalPtr->bbox[3] += deltaY;
  905.     ComputeRectOvalBbox(canvas, rectOvalPtr);
  906. }
  907.  
  908. /*
  909.  *--------------------------------------------------------------
  910.  *
  911.  * RectOvalToPostscript --
  912.  *
  913.  *    This procedure is called to generate Postscript for
  914.  *    rectangle and oval items.
  915.  *
  916.  * Results:
  917.  *    The return value is a standard Tcl result.  If an error
  918.  *    occurs in generating Postscript then an error message is
  919.  *    left in interp->result, replacing whatever used to be there.
  920.  *    If no error occurs, then Postscript for the rectangle is
  921.  *    appended to the result.
  922.  *
  923.  * Side effects:
  924.  *    None.
  925.  *
  926.  *--------------------------------------------------------------
  927.  */
  928.  
  929. static int
  930. RectOvalToPostscript(interp, canvas, itemPtr, prepass)
  931.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  932.     Tk_Canvas canvas;            /* Information about overall canvas. */
  933.     Tk_Item *itemPtr;            /* Item for which Postscript is
  934.                      * wanted. */
  935.     int prepass;            /* 1 means this is a prepass to
  936.                      * collect font information;  0 means
  937.                      * final Postscript is being created. */
  938. {
  939.     char pathCmd[500], string[100];
  940.     RectOvalItem *rectOvalPtr = (RectOvalItem *) itemPtr;
  941.     double y1, y2;
  942.  
  943.     y1 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[1]);
  944.     y2 = Tk_CanvasPsY(canvas, rectOvalPtr->bbox[3]);
  945.  
  946.     /*
  947.      * Generate a string that creates a path for the rectangle or oval.
  948.      * This is the only part of the procedure's code that is type-
  949.      * specific.
  950.      */
  951.  
  952.  
  953.     if (rectOvalPtr->header.typePtr == &tkRectangleType) {
  954.     sprintf(pathCmd, "%.15g %.15g moveto %.15g 0 rlineto 0 %.15g rlineto %.15g 0 rlineto closepath\n",
  955.         rectOvalPtr->bbox[0], y1,
  956.         rectOvalPtr->bbox[2]-rectOvalPtr->bbox[0], y2-y1,
  957.         rectOvalPtr->bbox[0]-rectOvalPtr->bbox[2]);
  958.     } else {
  959.     sprintf(pathCmd, "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n",
  960.         (rectOvalPtr->bbox[0] + rectOvalPtr->bbox[2])/2, (y1 + y2)/2,
  961.         (rectOvalPtr->bbox[2] - rectOvalPtr->bbox[0])/2, (y1 - y2)/2);
  962.     }
  963.  
  964.     /*
  965.      * First draw the filled area of the rectangle.
  966.      */
  967.  
  968.     if (rectOvalPtr->fillColor != NULL) {
  969.     Tcl_AppendResult(interp, pathCmd, (char *) NULL);
  970.     if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->fillColor)
  971.         != TCL_OK) {
  972.         return TCL_ERROR;
  973.     }
  974.     if (rectOvalPtr->fillStipple != None) {
  975.         Tcl_AppendResult(interp, "clip ", (char *) NULL);
  976.         if (Tk_CanvasPsStipple(interp, canvas, rectOvalPtr->fillStipple)
  977.             != TCL_OK) {
  978.         return TCL_ERROR;
  979.         }
  980.         if (rectOvalPtr->outlineColor != NULL) {
  981.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  982.         }
  983.     } else {
  984.         Tcl_AppendResult(interp, "fill\n", (char *) NULL);
  985.     }
  986.     }
  987.  
  988.     /*
  989.      * Now draw the outline, if there is one.
  990.      */
  991.  
  992.     if (rectOvalPtr->outlineColor != NULL) {
  993.     Tcl_AppendResult(interp, pathCmd, (char *) NULL);
  994.     sprintf(string, "%d setlinewidth", rectOvalPtr->width);
  995.     Tcl_AppendResult(interp, string,
  996.         " 0 setlinejoin 2 setlinecap\n", (char *) NULL);
  997.     if (Tk_CanvasPsColor(interp, canvas, rectOvalPtr->outlineColor)
  998.         != TCL_OK) {
  999.         return TCL_ERROR;
  1000.     }
  1001.     Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
  1002.     }
  1003.     return TCL_OK;
  1004. }
  1005.